package com.piece.core.framework.util.collection;

import com.google.common.collect.Multimap;
import com.piece.core.framework.support.convert.Convert;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.util.Assert;
import java.math.BigDecimal;
import java.sql.Date;
import java.sql.Timestamp;
import java.util.*;
import java.util.function.Function;

/**
 * 获取map中值的工具类,自动进行类型转换
 */
public class MapUtil extends MapUtils {

    public static <K, V> Map<K, V> empty() {
        return Collections.emptyMap();
    }

    public static <K, V> MapBuilder<K, V> builder() {
        return builder(new HashMap());
    }

    public static <K, V> MapBuilder<K, V> builder(Map<K, V> map) {
        return new MapBuilder(map);
    }

    public static String getString(String key, Map<String, Object> map) {
        if (null == map || null == key)
            throw new IllegalArgumentException();
        if (!map.containsKey(key))
            return null;
        Object value = map.get(key);
        if (null == value)
            return null;
        return value.toString();
    }

    public static Integer getInteger(String key, Map<String, Object> map) {
        if (null == map || null == key)
            throw new IllegalArgumentException();
        if (!map.containsKey(key))
            return null;
        Object value = map.get(key);
        if (null == value)
            return null;
        if (value instanceof Integer)
            return (Integer) value;
        if (value instanceof String)
            return Integer.valueOf((String) value);
        // Date 不支持变成为date类型
        if (value instanceof Date)
            throw new ClassCastException();
        if (value instanceof Number)
            return ((Number) value).intValue();
        throw new ClassCastException();
    }

    public static Long getLong(String key, Map<String, Object> map) {
        if (null == map || null == key)
            throw new IllegalArgumentException();
        if (!map.containsKey(key))
            return null;
        Object value = map.get(key);
        if (null == value)
            return null;
        if (value instanceof Long)
            return (Long) value;
        if (value instanceof Number)
            return ((Number) value).longValue();
        if (value instanceof String)
            return Long.valueOf((String) value);
        if (value instanceof Date) {
            return (((Date) value).getTime());
        }
        if (value instanceof java.sql.Time) {
            return ((java.sql.Time) value).getTime();
        }
        if (value instanceof Timestamp) {
            return ((Timestamp) value).getTime();
        }

        throw new ClassCastException();
    }

    public static Double getDouble(String key, Map<String, Object> map) {
        if (null == map || null == key)
            throw new IllegalArgumentException();
        if (!map.containsKey(key))
            return null;
        Object value = map.get(key);
        if (null == value)
            return null;
        if (value instanceof Double)
            return (Double) value;
        if (value instanceof Number)
            return ((Number) value).doubleValue();
        if (value instanceof String)
            return Double.valueOf((String) value);
        throw new ClassCastException();
    }

    public static BigDecimal getBigDecimal(String key, Map<String, Object> map) {
        if (null == map || null == key)
            throw new IllegalArgumentException();
        if (!map.containsKey(key))
            return null;
        Object value = map.get(key);
        if (null == value)
            return null;
        if (value instanceof BigDecimal)
            return (BigDecimal) value;
        if (value instanceof Integer)
            return new BigDecimal((Integer) value);
        if (value instanceof Short)
            return new BigDecimal((Short) value);
        if (value instanceof Byte)
            return new BigDecimal((Byte) value);
        if (value instanceof Long)
            return new BigDecimal((Long) value);
        if (value instanceof Float)
            return new BigDecimal((Float) value);
        if (value instanceof Double)
            return new BigDecimal((Double) value);
        if (value instanceof Date) {
            return new BigDecimal(((Date) value).getTime());
        }
        if (value instanceof java.sql.Time) {
            return new BigDecimal(((java.sql.Time) value).getTime());
        }
        if (value instanceof Timestamp) {
            return new BigDecimal(((Timestamp) value).getTime());
        }
        if (value instanceof String) {
            if (!StringUtils.isEmpty((String) value))
                return new BigDecimal((String) value);
            else
                return null;
        }
        throw new ClassCastException();
    }

    /**
     * 获取日期
     */
    public static Date getDate(String key, Map<String, Object> map) {
        if (null == map || null == key)
            throw new IllegalArgumentException();
        if (!map.containsKey(key))
            return null;
        Object value = map.get(key);
        if (null == value)
            return null;
        else {
            if (value instanceof Date) {
                return (Date) value;
            } else if (value instanceof Timestamp) {
                return new Date(((Timestamp) value).getTime());
            }
        }
        return null;
    }

    /**
     * 获取日期
     */
    public static java.util.Date getTimestamp(String key, Map<String, Object> map) {
        if (null == map || null == key)
            throw new IllegalArgumentException();
        if (!map.containsKey(key))
            return null;
        Object value = map.get(key);
        if (null == value)
            return null;
        else {
            if (value instanceof Date) {
                return (Date) value;
            } else if (value instanceof Timestamp) {
                Timestamp timestamp = (Timestamp) value;
                return timestamp;
            }
        }
        return null;
    }

    /**
     * 从哈希表表中，获得 keys 对应的所有 value 数组
     */
    public static <K, V> List<V> getList(Multimap<K, V> multimap, Collection<K> keys) {
        List<V> result = new ArrayList<>();
        keys.forEach(k -> {
            Collection<V> values = multimap.get(k);
            if (ArrayUtil.isEmpty(values)) {
                return;
            }
            result.addAll(values);
        });
        return result;
    }

    /**
     * 将map中key为likeKey的value前后加上字符'%'，用于like查询
     */
    public static void toLikeValue(Map<String, Object> map, String... likeKey) {
        if (ArrayUtils.isEmpty(likeKey))
            return;
        for (String key : likeKey) {
            if (map.containsKey(key))
                map.put(key, "%" + map.get(key) + "%");
        }
    }

    /**
     * 如果value不为空 ，则放到map中
     */
    public static void putIfValueNotNull(Map<String, Object> map, String key, Object value) {
        Assert.notNull(map);
        Assert.hasText(key);
        if (null != value)
            map.put(key, value);
    }

    /**
     * 如果value不为空 ，则放到map中
     */
    public static void putIfValueNotEmpty(Map<String, Object> map, String key, String value) {
        Assert.notNull(map);
        Assert.hasText(key);
        if (!StringUtils.isEmpty(value))
            map.put(key, value);
    }

    public static boolean putIfAbsent(Map<String, Object> map, String key, String value) {
        Assert.notNull(map);
        Assert.hasText(key);

        return null != map.putIfAbsent(key, value);
    }

    public static boolean putAllIfAbsent(Map map, Function keyGenerator, Collection collection) {
        Assert.notNull(map);
        boolean modified = false;
        Iterator iterator = collection.iterator();

        while(iterator.hasNext()) {
            Object value = iterator.next();
            Object key = keyGenerator.apply(value);
            modified = null != map.putIfAbsent(key, value);
        }

        return modified;
    }

    /**
     * Map转换XML格式
     */
    public static String convertMap2Xml(Map<Object, Object> paraMap) {
        StringBuffer xmlStr = new StringBuffer();
        if (null != paraMap) {
            xmlStr.append("<xml>");
            Set<Object> keySet = paraMap.keySet();
            Iterator<Object> keyIte = keySet.iterator();
            while (keyIte.hasNext()) {
                String key = (String) keyIte.next();
                String val = String.valueOf(paraMap.get(key));
                xmlStr.append("<");
                xmlStr.append(key);
                xmlStr.append(">");
                xmlStr.append(val);
                xmlStr.append("</");
                xmlStr.append(key);
                xmlStr.append(">");
            }
            xmlStr.append("</xml>");
        }
        return xmlStr.toString();
    }

    /**
     * 过滤属性
     */
    public static <K, V> Map<K, V> filter(Map<K, V> map, K... keys) {
        Map<K, V> map2 = new HashMap<>();
        Object[] var3 = keys;
        int var4 = keys.length;

        for (int var5 = 0; var5 < var4; ++var5) {
            K key = (K) var3[var5];
            if (map.containsKey(key)) {
                map2.put(key, map.get(key));
            }
        }
        return map2;
    }

    public static <K, V> String join(Map<K, V> map, String separator, String keyValueSeparator, String... otherParams) {
        return join(map, separator, keyValueSeparator, false, otherParams);
    }

    public static String sortJoin(Map<?, ?> params, String separator, String keyValueSeparator, boolean isIgnoreNull, String... otherParams) {
        return join(sort(params), separator, keyValueSeparator, isIgnoreNull, otherParams);
    }

    public static <K, V> String joinIgnoreNull(Map<K, V> map, String separator, String keyValueSeparator, String... otherParams) {
        return join(map, separator, keyValueSeparator, true, otherParams);
    }

    public static <K, V> String join(Map<K, V> map, String separator, String keyValueSeparator, boolean isIgnoreNull, String... otherParams) {
        StringBuilder strBuilder = new StringBuilder();
        boolean isFirst = true;
        if (isNotEmpty(map)) {
            Iterator var7 = map.entrySet().iterator();

            label40:
            while(true) {
                Map.Entry entry;
                do {
                    if (!var7.hasNext()) {
                        break label40;
                    }

                    entry = (Map.Entry)var7.next();
                } while(isIgnoreNull && (entry.getKey() == null || entry.getValue() == null));

                if (isFirst) {
                    isFirst = false;
                } else {
                    strBuilder.append(separator);
                }

                strBuilder.append(Convert.toStr(entry.getKey())).append(keyValueSeparator).append(Convert.toStr(entry.getValue()));
            }
        }

        if (ArrayUtil.isNotEmpty(otherParams)) {
            String[] var11 = otherParams;
            int var12 = otherParams.length;

            for(int var9 = 0; var9 < var12; ++var9) {
                String otherParam = var11[var9];
                strBuilder.append(otherParam);
            }
        }

        return strBuilder.toString();
    }

    public static <K, V> TreeMap<K, V> sort(Map<K, V> map) {
        return sort(map, null);
    }

    public static <K, V> TreeMap<K, V> sort(Map<K, V> map, Comparator<? super K> comparator) {
        if (null == map) {
            return null;
        } else {
            if (map instanceof TreeMap) {
                TreeMap<K, V> result = (TreeMap)map;
                if (null == comparator || comparator.equals(result.comparator())) {
                    return result;
                }
            }

            TreeMap<K, V> treeMap = new TreeMap(comparator);
            if (!isEmpty(map)) {
                treeMap.putAll(map);
            }

            return treeMap;
        }
    }

    public static <K, V extends Comparable<? super V>> Map<K, V> sortByValue(Map<K, V> map, boolean isDesc) {
        Map<K, V> result = new LinkedHashMap();
        Comparator<Map.Entry<K, V>> entryComparator = Map.Entry.comparingByValue();
        if (isDesc) {
            entryComparator = entryComparator.reversed();
        }

        map.entrySet().stream().sorted(entryComparator).forEachOrdered((e) -> {
            result.put(e.getKey(), e.getValue());
        });
        return result;
    }
}
